/**
 * Copyright 2021 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef EXECUTE_GRAPH_ANY_VALUE_H
#define EXECUTE_GRAPH_ANY_VALUE_H
#include <new>
#include <functional>
namespace ge {
class AnyValue {
 public:

  AnyValue() = default;
  // todo 按照当前的实现思路，拷贝系列函数要加个copyer的callback，感觉不太好，再想想，暂时不提供这俩函数
  AnyValue(const AnyValue &other) = delete;
  AnyValue &operator=(const AnyValue &other) = delete;

  AnyValue(AnyValue &&other) noexcept {
    value_ = other.value_;
    deleter = other.deleter;
    other.value_ = nullptr;
    other.deleter = nullptr;
  }

  template<typename T>
  AnyValue(const T &value) {
    value_ = new (std::nothrow) T(value);
    if (value_ != nullptr) {
      deleter = [](void *p){delete reinterpret_cast<T*>(p);};
    }
  }

  AnyValue(const char *p) {
    value_ = new (std::nothrow) std::string(p);
    if (value_ != nullptr) {
      deleter = [](void *p){delete reinterpret_cast<std::string *>(p);};
    }
  }

  AnyValue &operator=(AnyValue &&other) noexcept {
    Clear();
    value_ = other.value_;
    deleter = other.deleter;
    other.value_ = nullptr;
    other.deleter = nullptr;
    return *this;
  }
  template<typename T>
  AnyValue &operator=(const T &value) {
    Clear();
    value_ = new (std::nothrow) T(value);
    if (value_ != nullptr) {
      deleter = [](void *p){delete reinterpret_cast<T *>(p);};
    }
    return *this;
  }
  template<typename T>
  AnyValue &operator=(T &&value) {
    Clear();
    value_ = new (std::nothrow) T(std::forward<T>(value));
    if (value_ != nullptr) {
      deleter = [](void *p){delete reinterpret_cast<T*>(p);};
    }
    return *this;
  }
  AnyValue &operator=(const char *p) {
    Clear();
    value_ = new (std::nothrow) std::string(p);
    if (value_ != nullptr) {
      deleter = [](void *p){delete reinterpret_cast<std::string *>(p);};
    }
    return *this;
  }
  template<typename T>
  const T &Get() const {
    return *reinterpret_cast<T *>(value_);
  }
  template<typename T>
  T *MutableGet() {
    return reinterpret_cast<T *>(value_);
  }

  ~AnyValue() {
    Clear();
  }

 private:
  void Clear() {
    if (deleter != nullptr) {
      deleter(value_);
      deleter = nullptr;
    }
  }

 private:
  void *value_{nullptr};
  std::function<void(void *)> deleter{nullptr};
};
}

#endif  //EXECUTE_GRAPH_ANY_VALUE_H
